home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint96sb.zoo / src / proc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-14  |  11.7 KB  |  569 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /* routines for handling processes */
  6.  
  7. #include "mint.h"
  8. #include "xbra.h"
  9.  
  10. static void do_wakeup_things P_((void));
  11.  
  12. extern short proc_clock;
  13.  
  14. /* global process variables */
  15. PROC *proclist;            /* list of all active processes */
  16. PROC *curproc;            /* current process        */
  17. PROC *rootproc;            /* pid 0 -- MiNT itself        */
  18. PROC *sys_q[NUM_QUEUES];
  19.  
  20. #define TIME_SLICE    1    /* number of 20ms ticks before process is
  21.                    pre-empted */
  22.  
  23.  
  24. /* macro for calculating number of missed time slices, based on a
  25.  * process' priority
  26.  */
  27. #define SLICES(pri)    (((pri) >= 0) ? 0 : -(pri))
  28.  
  29. extern FILESYS bios_filesys;
  30.  
  31. /*
  32.  * get a new process struct
  33.  */
  34.  
  35. PROC *
  36. new_proc()
  37. {
  38.     PROC *p;
  39.  
  40.     p = (PROC *)kmalloc(SIZEOF(PROC));
  41.     return p;
  42. }
  43.  
  44. /*
  45.  * dispose of an old proc
  46.  */
  47.  
  48. void
  49. dispose_proc(p)
  50.     PROC *p;
  51. {
  52.     kfree(p);
  53. }
  54.  
  55. /*
  56.  * create a new process that is (practically) a duplicate of the
  57.  * current one
  58.  */
  59.  
  60. PROC *
  61. fork_proc()
  62. {
  63.     PROC *p;
  64.     int i;
  65.     FILEPTR *f;
  66.  
  67.     if ((p = new_proc()) == 0) {
  68. nomem:
  69.         DEBUG(("fork_proc: insufficient memory"));
  70.         mint_errno = ENSMEM; return 0;
  71.     }
  72.  
  73.     *p = *curproc;    /* child shares most things with parent... */
  74.  
  75. /* ... except for these: */
  76.     p->ppid = curproc->pid;
  77.     p->pid = newpid();
  78.     p->sigpending = 0;
  79.     p->sysstack = (long)(p->stack + STKSIZE - 12);
  80.     p->ctxt[CURRENT].ssp = p->sysstack;
  81.     p->ctxt[SYSCALL].ssp = (long)(p->stack + ISTKSIZE);
  82.     p->alarmtim = 0;
  83.     p->curpri = p->pri;
  84.     p->slices = SLICES(p->pri);
  85.     p->starttime = timestamp;
  86.     p->startdate = datestamp;
  87.  
  88.     ((long *)p->sysstack)[1] = FRAME_MAGIC;
  89.     ((long *)p->sysstack)[2] = 0;
  90.     ((long *)p->sysstack)[3] = 0;
  91.  
  92.     p->usrtime = p->systime = p->chldstime = p->chldutime = 0;
  93.  
  94. /* copy open handles */
  95.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  96.         if ((f = p->handle[i]) != 0) {
  97.             if (f->flags & O_NOINHERIT)
  98.         /* oops, we didn't really want to copy this handle */
  99.                 p->handle[i] = 0;
  100.             else
  101.                 f->links++;
  102.         }
  103.     }
  104.  
  105. /* clear directory search info */
  106.     zero((char *)p->srchdta, NUM_SEARCH * SIZEOF(DTABUF *));
  107.  
  108. /* copy memory */
  109.     p->mem = (MEMREGION **) kmalloc(p->num_reg * SIZEOF(MEMREGION *));
  110.     if (!p->mem) {
  111.         dispose_proc(p);
  112.         goto nomem;
  113.     }
  114.     p->addr = (virtaddr *)kmalloc(p->num_reg * SIZEOF(virtaddr));
  115.     if (!p->addr) {
  116.         kfree(p->mem);
  117.         dispose_proc(p);
  118.         goto nomem;
  119.     }
  120.  
  121.     for (i = 0; i < curproc->num_reg; i++) {
  122.         p->mem[i] = curproc->mem[i];
  123.         if (p->mem[i] != 0)
  124.             p->mem[i]->links++;
  125.         p->addr[i] = curproc->addr[i];
  126.     }
  127.  
  128. /* child isn't traced */
  129.     p->ptracer = 0;
  130.     p->ptraceflags = 0;
  131.  
  132.     p->starttime = Tgettime();
  133.     p->startdate = Tgetdate();
  134.  
  135.     p->q_next = 0;
  136.     p->wait_q = 0;
  137.     p->gl_next = proclist;
  138.     proclist = p;            /* hook into the process list */
  139.     return p;
  140. }
  141.  
  142. /*
  143.  * initialize the process table
  144.  */
  145.  
  146. void
  147. init_proc()
  148. {
  149.     int i;
  150.     FILESYS *fs;
  151.     fcookie dir;
  152.  
  153.     rootproc = curproc = new_proc();
  154.     assert(curproc);
  155.  
  156.     zero((char *)curproc, (long)sizeof(PROC));
  157.  
  158.     curproc->ppid = -1;        /* no parent */
  159.     curproc->domain = DOM_TOS;    /* TOS domain */
  160.     curproc->sysstack = (long) (curproc->stack+STKSIZE-12);
  161.     curproc->magic = CTXT_MAGIC;
  162.     ((long *)curproc->sysstack)[1] = FRAME_MAGIC;
  163.     ((long *)curproc->sysstack)[2] = 0;
  164.     ((long *)curproc->sysstack)[3] = 0;
  165.  
  166. /* NOTE: in main.c this could be changed, later */
  167.     curproc->base = _base;
  168.  
  169.     strcpy(curproc->name, "MiNT");
  170.  
  171. /* get some memory */
  172.     curproc->mem = (MEMREGION **)kmalloc(NUM_REGIONS*SIZEOF(MEMREGION *));
  173.     curproc->addr = (virtaddr *)kmalloc(NUM_REGIONS*SIZEOF(virtaddr));
  174.     assert(curproc->mem && curproc->addr);
  175.  
  176. /* make sure it's filled with zeros */
  177.     zero((char *)curproc->addr, NUM_REGIONS * SIZEOF(virtaddr));
  178.     zero((char *)curproc->mem, NUM_REGIONS * SIZEOF(MEMREGION *));
  179.     curproc->num_reg = NUM_REGIONS;
  180.  
  181. /* get root and current directories for all drives */
  182.     for (i = 0; i < NUM_DRIVES; i++) {
  183.         if ((fs = drives[i]) != 0 && (*fs->root)(i, &dir) == E_OK) {
  184.                 curproc->root[i] = curproc->curdir[i] = dir;
  185.         } else {
  186.             curproc->root[i].fs = curproc->curdir[i].fs = 0;
  187.             curproc->root[i].dev = curproc->curdir[i].dev = i;
  188.         }
  189.     }
  190.  
  191. /* Set the correct drive. The current directory we
  192.  * set later, after all file systems have been loaded.
  193.  */
  194.  
  195.     curproc->curdrv = Dgetdrv();
  196.     proclist = curproc;
  197.  
  198.     curproc->umask = 0;
  199.  
  200. /*
  201.  * some more protection against job control; unless these signals are
  202.  * re-activated by a shell that knows about job control, they'll have
  203.  * no effect
  204.  */
  205.     curproc->sighandle[SIGTTIN] = curproc->sighandle[SIGTTOU] =
  206.         curproc->sighandle[SIGTSTP] = SIG_IGN;
  207.  
  208. /* set up some more per-process variables */
  209.     curproc->starttime = Tgettime();
  210.     curproc->startdate = Tgetdate();
  211.     if (has_bconmap)
  212.         curproc->bconmap = curbconmap;
  213.     else
  214.         curproc->bconmap = 1;
  215.  
  216.     curproc->logbase = (void *)Logbase();
  217.     curproc->criticerr = *((long ARGS_ON_STACK (**) P_((long)))0x404L);
  218. }
  219.  
  220. /*
  221.  * reset all process priorities to their base level
  222.  * called once per second, so that cpu hogs can get _some_ time
  223.  * slices :-).
  224.  */
  225.  
  226. void
  227. reset_priorities()
  228. {
  229.     PROC *p;
  230.  
  231.     for (p = proclist; p; p = p->gl_next) {
  232.         p->curpri = p->pri;
  233.         p->slices = SLICES(p->curpri);
  234.     }
  235. }
  236.  
  237. /*
  238.  * more priority code stuff:
  239.  * run_next(p, slices): schedule process "p" to run next, with "slices"
  240.  *       initial time slices; "p" does not actually start running until
  241.  *       the next context switch
  242.  * fresh_slices(slices): give the current process "slices" more slices in
  243.  *       which to run
  244.  */
  245.  
  246. void
  247. run_next(p, slices)
  248.     PROC *p;
  249.     int slices;    /* BUG: currently ignored */
  250. {
  251.     UNUSED(slices);
  252.  
  253.     p->slices = 0;
  254.     p->curpri = MAX_NICE;
  255.     p->wait_q = READY_Q;
  256.     p->q_next = sys_q[READY_Q];
  257.     sys_q[READY_Q] = p;
  258. }
  259.  
  260. void
  261. fresh_slices(slices)
  262.     int slices;
  263. {
  264.     curproc->slices = 0;
  265.     curproc->curpri = MAX_NICE+1;
  266.     proc_clock = slices;
  267. }
  268.  
  269. /*
  270.  * add a process to a wait (or ready) queue.
  271.  *
  272.  * processes go onto a queue in first in-first out order
  273.  */
  274.  
  275. void
  276. add_q(que, proc)
  277.     int que;
  278.     PROC *proc;
  279. {
  280.     PROC *q, **lastq;
  281.  
  282. /* "proc" should not already be on a list */
  283.     assert(proc->wait_q == 0);
  284.     assert(proc->q_next == 0);
  285.  
  286.     lastq = &sys_q[que];
  287.     q = *lastq;
  288.     while(q) {
  289.         lastq = &q->q_next;
  290.         q = *lastq;
  291.     }
  292.     *lastq = proc;
  293.     proc->wait_q = que;
  294.     if (que != READY_Q) {
  295.         proc->curpri = proc->pri;    /* reward the process */
  296.         proc->slices = SLICES(proc->curpri);
  297.     }
  298. }
  299.  
  300. /*
  301.  * remove a process from a queue
  302.  */
  303.  
  304. void
  305. rm_q(que, proc)
  306.     int que;
  307.     PROC *proc;
  308. {
  309.     PROC *q;
  310.     PROC *old = 0;
  311.  
  312.     assert(proc->wait_q == que);
  313.  
  314.     q = sys_q[que];
  315.     while (q && q != proc) {
  316.         old = q;
  317.         q = q->q_next;
  318.     }
  319.     if (q == 0)
  320.         FATAL("rm_q: unable to remove process from queue");
  321.  
  322.     if (old)
  323.         old->q_next = proc->q_next;
  324.     else
  325.         sys_q[que] = proc->q_next;
  326.  
  327.     proc->wait_q = 0;
  328.     proc->q_next = 0;
  329. }
  330.  
  331. /*
  332.  * preempt(): called by the vbl routine and/or the trap handlers when
  333.  * they detect that a process has exceeded its time slice and hasn't
  334.  * yielded gracefully. For now, it just does sleep(READY_Q); later,
  335.  * we might want to keep track of statistics or something.
  336.  */
  337.  
  338. void ARGS_ON_STACK
  339. preempt()
  340. {
  341.     extern short bconbsiz;    /* in bios.c */
  342.  
  343.     if (bconbsiz)
  344.         (void)bflush();
  345.     else {
  346.         /* punish the pre-empted process */
  347.         if (curproc->curpri >= MIN_NICE)
  348.             curproc->curpri -= 1;
  349.     }
  350.     sleep(READY_Q, curproc->wait_cond);
  351. }
  352.  
  353. /*
  354.  * sleep(que, cond): put the current process on the given queue, then switch
  355.  * contexts. Before a new process runs, give it a fresh time slice. "cond"
  356.  * is the condition for which the process is waiting, and is placed in
  357.  * curproc->wait_cond
  358.  */
  359.  
  360. static void
  361. do_wakeup_things()
  362. {
  363. /*
  364.  * check for stack underflow, just in case
  365.  */
  366.     auto int foo;
  367.     PROC *p;
  368.  
  369.     p = curproc;
  370.  
  371.     if ( p->pid != 0 &&
  372.          ((long)&foo) < (long)p->stack + ISTKSIZE + 512 ) {
  373.         ALERT("stack underflow");
  374.         handle_sig(SIGBUS);
  375.     }
  376.  
  377. /* see if process' time limit has been exceeded */
  378.  
  379.     if (p->maxcpu) {
  380.         if (p->maxcpu <= p->systime + p->usrtime) {
  381.             DEBUG(("cpu limit exceeded"));
  382.             raise(SIGXCPU);
  383.         }
  384.     }
  385.  
  386. /*
  387.  * check for alarms and similar time out stuff (see timeout.c)
  388.  */
  389.  
  390.     checkalarms();
  391.     if (p->sigpending)
  392.         check_sigs();        /* check for signals */
  393.  
  394.     proc_clock = TIME_SLICE;    /* get a fresh time slice */
  395.     p->slices = SLICES(p->curpri);
  396. }
  397.  
  398. void ARGS_ON_STACK 
  399. sleep(que, cond)
  400.     int que;
  401.     long cond;
  402. {
  403.     PROC *p;
  404.     short sr;
  405.     extern short kintr;    /* in bios.c */
  406. #ifdef FASTTEXT
  407.     extern int hardscroll;    /* in fasttext.c */
  408. #endif
  409.  
  410. /*
  411.  * if there have been keyboard interrupts since our last sleep, check for
  412.  * special keys like CTRL-ALT-Fx
  413.  */
  414.  
  415.     if (kintr) {
  416.         (void)checkkeys();
  417.         kintr = 0;
  418.     }
  419.  
  420.     if (que == READY_Q && !sys_q[READY_Q]) {
  421. /* we're just going to wake up again right away! */
  422.         do_wakeup_things();
  423.         return;
  424.     }
  425.  
  426.     sr = spl7();
  427.  
  428.     add_q(que, curproc);
  429.     curproc->wait_cond = cond;
  430.  
  431.     if (!sys_q[READY_Q]) {
  432. /* hmm, no-one is ready to run. might be a deadlock, might not.
  433.  * first, try waking up any napping processes; if that doesn't work,
  434.  * run the root process, just so we have someone to charge time
  435.  * to.
  436.  */
  437.         wake(SELECT_Q, (long)nap);
  438.         if (!sys_q[READY_Q]) {
  439.             p = rootproc;        /* pid 0 */
  440.             rm_q(p->wait_q, p);
  441.             add_q(READY_Q, p);
  442.         }
  443.     }
  444.  
  445. /*
  446.  * Walk through the ready list, to find what process should run next.
  447.  * Lower priority processes don't get to run every time through this
  448.  * loop; if "p->slices" is positive, it's the number of times that they
  449.  * will have to miss a turn before getting to run again
  450.  */
  451.     p = 0;
  452.  
  453.     while (!p) {
  454.         for (p = sys_q[READY_Q]; p; p = p->q_next) {
  455.             if (p->slices > 0)
  456.                 p->slices--;
  457.             else
  458.                 break;
  459.         }
  460.     }
  461.     rm_q(READY_Q, p);
  462.  
  463.     spl(sr);
  464.  
  465.     if (save_context(&(curproc->ctxt[CURRENT]))) {
  466. /*
  467.  * restore per-process variables here
  468.  */
  469. #ifdef FASTTEXT
  470.         if (!hardscroll)
  471. #endif
  472.             *((void **)0x44eL) = curproc->logbase;
  473.         do_wakeup_things();
  474.         return;
  475.     }
  476. /*
  477.  * save per-process variables here
  478.  */
  479. #ifdef FASTTEXT
  480.     if (!hardscroll)
  481. #endif
  482.         curproc->logbase = *((void **)0x44eL);
  483.     curproc->ctxt[CURRENT].regs[0] = 1;
  484.     curproc = p;
  485.     proc_clock = TIME_SLICE;    /* fresh time */
  486.     if ((p->ctxt[CURRENT].sr & 0x2000) == 0) {    /* user mode? */
  487.         leave_kernel();
  488.     }
  489.     assert(p->magic == CTXT_MAGIC);
  490.     restore_context(&(p->ctxt[CURRENT]));
  491. }
  492.  
  493. /*
  494.  * wake(que, cond): wake up all processes on the given queue that are waiting
  495.  * for the indicated condition
  496.  */
  497.  
  498. void ARGS_ON_STACK 
  499. wake(que, cond)
  500.     int que;
  501.     long cond;
  502. {
  503.     PROC *p;
  504.  
  505.     if (que == READY_Q) {
  506.         ALERT("wake: why wake up ready processes??");
  507.         return;
  508.     }
  509. top:
  510.     for(p = sys_q[que]; p; p = p->q_next) {
  511.         if (p->wait_cond == cond) {
  512.             rm_q(que, p);
  513.             add_q(READY_Q, p);
  514.             goto top;
  515.         }
  516.     }
  517. }
  518.  
  519. /*
  520.  * wakeselect(p): wake process p from a select() system call
  521.  * may be called by an interrupt handler or whatever
  522.  */
  523.  
  524. void ARGS_ON_STACK 
  525. wakeselect(param)
  526.     long param;
  527. {
  528.     PROC *p = (PROC *)param;
  529.     short s;
  530.  
  531.     s = spl7();    /* block interrupts */
  532.     if(p->wait_cond == (long)wakeselect) {
  533.         p->wait_cond = 0;
  534.     }
  535.     if (p->wait_q == SELECT_Q) {
  536.         rm_q(SELECT_Q, p);
  537.         add_q(READY_Q, p);
  538.     }
  539.     spl(s);
  540. }
  541.  
  542. /*
  543.  * dump out information about processes
  544.  */
  545.  
  546. /*
  547.  * kludge alert! In order to get the right pid printed by ALERT, we use
  548.  * curproc as the loop variable.
  549.  */
  550.  
  551. void
  552. DUMPPROC()
  553. {
  554. #ifndef NO_DEBUG_INFO
  555.     PROC *p = curproc;
  556.  
  557.     for (curproc = proclist; curproc; curproc = curproc->gl_next) {
  558.         ALERT("queue %d cond %lx PC: %lx USP: %lx SSP: %lx SYSSP: %lx",
  559.         curproc->wait_q, curproc->wait_cond,
  560.         curproc->ctxt[SYSCALL].pc,
  561.         curproc->ctxt[SYSCALL].usp,
  562.         curproc->ctxt[SYSCALL].ssp,
  563.         curproc->sysstack
  564.         );
  565.     }
  566.     curproc = p;        /* restore the real curproc */
  567. #endif
  568. }
  569.